package com.cloudkinto.service.storage.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.MathUtils;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.extentity.ProductStockDetailDto;
import com.cloudkinto.extentity.shelf.Item;
import com.cloudkinto.extentity.shelf.ShelfSortUpdateDto;
import com.cloudkinto.extentity.shelf.StoragePreviewDto;
import com.cloudkinto.extentity.stock.PositionOutVolRes;
import com.cloudkinto.service.analysis.vo.InitRes;
import com.cloudkinto.service.message.MessageNoticeService;
import com.cloudkinto.service.storage.StoragePositionService;
import com.cloudkinto.service.storage.StorageShelfService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;

import com.cloudkinto.service.storage.vo.*;
import com.cloudkinto.utils.BarCodePdfUtils;
import lombok.Data;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author zhujiale
 * @since 2022-12-20
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class StorageShelfServiceImpl extends ServiceImpl<StorageShelfDao, StorageShelfDo> implements StorageShelfService {
    @Autowired
    private StorageShelfDao dao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private StoragePositionDao positionDao;
    @Autowired
    private StorageShelfGirdDao storageShelfGirdDao;
    @Autowired
    private StoragePositionService positionService;
    @Autowired
    private ProductStockRackDao productStockRackDao;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private StorageShowRuleDao storageShowRuleDao;
    @Autowired
    private MessageNoticeService messageNoticeService;
    @Autowired
    private ProductOutDao productOutDao;

    @Override
    public SingleResult addInit() {
        List<StorageDo> storageDos = storageDao.selectList(new QueryWrapper<StorageDo>());
        List<InitRes> resList = new ArrayList<>();
        for (StorageDo et : storageDos) {
            InitRes res = new InitRes();
            res.setId(et.getId());
            res.setName(et.getStorageName());
            resList.add(res);
        }
        return SingleResult.success(resList);
    }

    @Override
    public Object add(StorageShelfAddReq req, Long userId, Long companyId) {
        if (req.getShelfName().contains("-")) {
            throw new BizException(SysConstant.Shelf_Add_Error);
        }
        StorageShelfDo entityDo = new StorageShelfDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setCompanyId(companyId);
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        if (null == req.getGridNum()) {
            entityDo.setGridNum(1);
        }
        if (null == req.getGridFrom()) {
            entityDo.setGridFrom(1);
        }
        addCheck(req);
        dao.insert(entityDo);

        int shelfNum = entityDo.getBarCodeFrom();
        int sortNum = entityDo.getSort();
        //算好库位名称生成到库位表
        for (int i = 1; i <= entityDo.getShelfNum(); i++) {
            for (int j = 1; j <= entityDo.getGridNum(); j++) {
                for (int k = 1; k <= entityDo.getTierNum(); k++) {
                    int a = shelfNum++;
                    int b = sortNum++;
                    StringBuilder sb = new StringBuilder();
                    sb.append(entityDo.getShelfName());
                    //sb.append("-");
                    sb.append(i + "-");
                    sb.append(j);
                    //只有一个格子不管第三层
                    if (null != req.getGridNum()) {
                        sb.append("-" + k);
                    }
                    StoragePositionDo positionDo = new StoragePositionDo();
                    positionDo.setShelfId(entityDo.getId());
                    positionDo.setPositionName(sb.toString());
                    positionDo.setShelfNum(Long.valueOf(a));
                    positionDo.setCreateBy(userId);
                    positionDo.setCreateTime(new Date());
                    positionDao.insert(positionDo);
                }
            }
        }

        if (entityDo.getShelfSort() != null && entityDo.getFirstType() != null && entityDo.getGangway() != null) {
            ShelfSortUpdateReq updateReq = new ShelfSortUpdateReq();
            BeanUtils.copyProperties(entityDo, updateReq);
            this.updateSort(updateReq, userId);
        }
        return entityDo;
    }

    //新增校验
    private void addCheck(StorageShelfAddReq req) {
        int count = dao.selectCount(new QueryWrapper<StorageShelfDo>().eq("area_name", req.getAreaName()).eq("storage_id", req.getStorageId()));
        if (count > 0) {
            throw new BizException(SysConstant.StorageShelf_Check_AreaName);
        }
        int count1 = dao.selectCount(new QueryWrapper<StorageShelfDo>().eq("storage_id", req.getStorageId()).eq("shelf_name", req.getShelfName()));
        if (count1 > 0) {
            throw new BizException(SysConstant.StorageShelf_Check_ShelfName);
        }
    }


    @Override
    public SingleResult updateInit(Long id) {
        StorageShelfDo shelfDo = dao.selectById(id);
        return SingleResult.success(shelfDo);
    }

    @Override
    public Object update(StorageShelfUpdateReq req, Long userId, Long companyId) {
//        if (req.getShelfName().contains("-")) {
//            throw new BizException(SysConstant.Shelf_Add_Error);
//        }
        StorageShelfDo et = dao.selectById(req.getId());
        if (et == null) {
            throw new BizException(SysConstant.Error_Data_NotExist);
        }
        if (req.getShelfType() == null) {
            req.setShelfType(et.getShelfType());
        }
        BeanUtils.copyProperties(req, et);
        dao.updateById(et);
        if (et.getConfig() == 0) {
            this.updatePositionSort(et);
        }
        else {
            this.updateConfigSort(et);
        }
        return "修改成功";
    }


    /**
     * 设置 拣货顺序
     */
    @Override
    public void updateSort(ShelfSortUpdateReq updateReq, Long userId) {
        StorageShelfDo et = dao.selectById(updateReq.getId());
        if (et == null) {
            throw new BizException(SysConstant.Error_Data_NotExist);
        }
        if (updateReq.getShelfType() == null) {
            updateReq.setShelfType(et.getShelfType());
        }
        BeanUtils.copyProperties(updateReq, et);
        dao.updateById(et);
        if (et.getConfig() == 0) {
            this.updatePositionSort(et);
        }
        else {
            this.updateConfigSort(et);
        }
    }

     public void updateConfigSort(StorageShelfDo et) {
         List<ShelfSortUpdateDto> list = positionDao.getSortPosList(et.getId());
         //按货架分类
         Map<Integer, List<ShelfSortUpdateDto>> listMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getShelfNumber));

         LambdaQueryWrapper<StorageShelfGirdDo> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(StorageShelfGirdDo::getShelfId, et.getId());
         if (et.getShelfSort() == 1) {
             queryWrapper.orderByDesc(StorageShelfGirdDo::getShelf);
         }
         else {
             queryWrapper.orderByAsc(StorageShelfGirdDo::getShelf);
         }
         List<StorageShelfGirdDo> shelfGirdDoList = storageShelfGirdDao.selectList(queryWrapper);



         Map<Integer, Integer> girdTypeMap = new HashMap<>();
         for (StorageShelfGirdDo storageShelfGirdDo : shelfGirdDoList) {
             girdTypeMap.put(storageShelfGirdDo.getSort(), storageShelfGirdDo.getShelf());
         }
        // 奇数 right 则增加 奇数在左侧则减少   偶数在right 则减少 偶数在left 则增加
         //奇数增加 偶数减少
         int rackSort = 1;
         for (Integer sort : girdTypeMap.keySet()) {
             Integer shelf = girdTypeMap.get(sort);
             //货架中在 按照格子分类
             Map<Integer, List<ShelfSortUpdateDto>> gridListMap = listMap.get(shelf).stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
             List<Integer> gridList = new ArrayList<>(gridListMap.keySet());
             if (sort % 2 == 1) {
                 //奇数 排序增加
             }
             else {
                 //偶数 排序减少
                 Collections.reverse(gridList);
             }
             rackSort = this.updateWrapper(gridList, gridListMap, rackSort);

         }
     }


    /**
     * 更新单列 货架拣货顺序
     * @param et
     */
    public void updatePositionSort(StorageShelfDo et) {
        //再去设置 库位拣货顺序
        List<ShelfSortUpdateDto> list = positionDao.getSortPosList(et.getId());
        //按照货架分类
        Map<Integer, List<ShelfSortUpdateDto>> listMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getShelfNumber));
        List<Integer> shelfList = new ArrayList<>(listMap.keySet());
        //shelf_type 货架顺序类型 0 逆序 1顺序 shelf_sort 货架拣货顺序， 0 顺序 1逆序
//        if ((et.getShelfType() == 0 && et.getShelfSort() == 1) || (et.getShelfType() == 1 && et.getShelfSort() == 1)) {
//            Collections.reverse(shelfList);
//        }

        if ((et.getShelfType() == 0 && et.getShelfSort() == 1) || (et.getShelfType() == 1 && et.getShelfSort() == 1)) {
            Collections.reverse(shelfList);
        }
        //如果逆序拣货。重新判断起始货架 是单还是双货架
        et.setFirstType(this.jugFirstType(et, shelfList.size()));
        int sort = 1;
        for (int i = 0; i < shelfList.size(); i++) {
            //单货架中在 按照格子分类
            Map<Integer, List<ShelfSortUpdateDto>> gridListMap = listMap.get(shelfList.get(i)).stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
            List<Integer> gridList = new ArrayList<>(gridListMap.keySet());

            if (et.getGangway() == 0 || et.getGangway() == 1) {
                if (et.getGangway() == 0) {
                    if (et.getFirstType() == 0) {
                        if (i % 2 != 0) {
                            Collections.reverse(gridList);
                        }
                    } else {
                        if (i % 2 == 0) {
                            Collections.reverse(gridList);
                        }
                    }
                } else {
                    //过道在右侧
                    if (et.getFirstType() == 0) {
                        if (i % 2 == 0) {
                            Collections.reverse(gridList);
                        }
                    } else {
                        if (i % 2 != 0) {
                            Collections.reverse(gridList);
                        }
                    }
                }
//                if (i == 0 && updateReq.getGangway() == 0) {
//                    //过道在左侧
//                    Collections.reverse(gridList);
//                }
//                if (i != 0 && i % 2 == 0) {
//                    Collections.reverse(gridList);
//                }
                sort = this.updateWrapper(gridList, gridListMap, sort);
            } else if (et.getGangway() == 3 || et.getGangway() == 4) {
                if (et.getGangway() == 4) {
                    //过道在格子之间
                    if (et.getBeginGrid() + 1 != et.getEndGrid()) {
                        throw new BizException(SysConstant.Shelf_Sort_Error);
                    }
                }
                //3过道在格子上
                if (gridList.size() < et.getEndGrid()) {
                    throw new BizException(SysConstant.Shelf_Sort_GirdCount_Error);
                }
                int shelfIndex = i;
//                if ((et.getShelfType() == 0 && et.getShelfSort() == 1) || (et.getShelfType() == 1 && et.getShelfSort() == 1)) {
                    if (et.getFirstType() == 0) {
                        //单货架
                    } else if (et.getFirstType() == 1) {
                        //双货架
                        shelfIndex += 1;
                    }
//                }
                if ((shelfIndex + 1) % 2 != 0) {
                    //奇数情况 1 3 5 从过道开始
                    for (int j = et.getBeginGrid() - 1; j >= 0; j--) {
                        for (ShelfSortUpdateDto shelfSortUpdateDto : gridListMap.get(gridList.get(j))) {
                            LambdaUpdateWrapper<StoragePositionDo> updateWrapper = this.getWrapper(shelfSortUpdateDto.getId(), sort++);
                            positionService.update(updateWrapper);
                        }
                    }
                    int rightSort = sort;
                    if (i + 1 < shelfList.size()) {
                        rightSort += listMap.get(shelfList.get(i)).size();
                    }
                    for (int j = gridList.size() - 1; j >= et.getBeginGrid(); j--) {
                        for (ShelfSortUpdateDto shelfSortUpdateDto : gridListMap.get(gridList.get(j))) {
                            LambdaUpdateWrapper<StoragePositionDo> updateWrapper = this.getWrapper(shelfSortUpdateDto.getId(), rightSort++);
                            positionService.update(updateWrapper);
                        }
                    }
                } else {
                    //偶数情况 直接顺序 12345
                    sort = this.updateWrapper(gridList, gridListMap, sort);
                    //sort 加上右边的序号
                    sort += (gridList.size() - et.getBeginGrid()) * et.getTierNum();
                }
            }

        }
    }

    //如果逆序拣货。重新判断起始货架 是单还是双货架
    public Integer jugFirstType(StorageShelfDo et, int shelfCount) {
        Integer firstType = et.getFirstType();
        //shelfSort 货架拣货顺序， 0 顺序 1逆序
        if (et.getShelfSort() == 1) {
            if (et.getFirstType() == 0) {
                shelfCount -= 1;
            }
            if (shelfCount % 2 == 0) {
                //说明是双货架
                firstType = 1;
            } else {
                //单货架
                firstType = 0;
            }
        }
        return firstType;
    }

    public Integer jugFirstTypeNew(StorageShelfDo et, int shelfCount) {
        Integer firstType = et.getFirstType();
        if (et.getShelfType() == 0) {
            if (et.getFirstType() == 0) {
                shelfCount -= 1;
            }
            if (shelfCount % 2 == 0) {
                //说明是双货架
                firstType = 1;
            } else {
                //单货架
                firstType = 0;
            }
        }
        return firstType;
    }

    public int updateWrapper(List<Integer> gridList, Map<Integer, List<ShelfSortUpdateDto>> gridListMap, int sort) {
        for (int j = 0; j < gridList.size(); j++) {
            for (ShelfSortUpdateDto shelfSortUpdateDto : gridListMap.get(gridList.get(j))) {
                LambdaUpdateWrapper<StoragePositionDo> updateWrapper = this.getWrapper(shelfSortUpdateDto.getId(), sort++);
                positionService.update(updateWrapper);
            }
        }
        return sort;
    }

    public LambdaUpdateWrapper<StoragePositionDo> getWrapper(Long id, Integer rackSort) {
        LambdaUpdateWrapper<StoragePositionDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoragePositionDo::getId, id);
        updateWrapper.set(StoragePositionDo::getRackSort, rackSort);
        return updateWrapper;
    }


    @Override
    public int delete(Long id, Long userId) {
        return dao.deleteById(id);
    }


    @Override
    public Object detail(Long id) {
        StorageShelfDo entityDo = dao.selectById(id);
        List<StorageShelfRes> resList = new ArrayList<>();
        int shelfNum = entityDo.getBarCodeFrom();
        int sortNum = entityDo.getSort();
        for (int i = 1; i <= entityDo.getShelfNum(); i++) {
            for (int j = 1; j <= entityDo.getGridNum(); j++) {
                for (int k = 1; k <= entityDo.getTierNum(); k++) {
                    int a = shelfNum++;
                    int b = sortNum++;
                    StringBuilder sb = new StringBuilder();
                    sb.append(entityDo.getShelfName());
                    //sb.append("-");
                    sb.append(i).append("-");
                    sb.append(j);
                    //只有一个格子不管第三层
                    if (entityDo.getGridNum() == 1) {
                        sb.append("-").append(k);
                    }
                    StorageShelfRes res = new StorageShelfRes();
                    res.setShelfName(sb.toString());
                    res.setBarCodeFrom(a);
                    res.setStockCapacity(entityDo.getStockCapacity());
                    res.setSort(b);
                    res.setTypeCN(StringsUtil.createI18Message(entityDo.getType() == 1 ? SysConstant.StorageShelf_SMALL : SysConstant.StorageShelf_Big));
                    res.setStatusCN(StringsUtil.createI18Message(entityDo.getStatus() == 1 ? SysConstant.Enable : SysConstant.Unable));
                    StorageDo storageDo = storageDao.selectById(entityDo.getStorageId());
                    if (null != storageDo) {
                        res.setStorageCN(storageDo.getStorageName());
                    }
                    resList.add(res);
                }
            }
        }
        return handlerDetailAfter(resList);
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        return SingleResult.success("");
    }


    @Override
    public PageResult getListPage(Map<String, String> map) {
        QueryWrapper<StorageShelfDo> wrapper = queryBuild(map);
        IPage<StorageShelfDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<StorageShelfDo> shelfDos = page.getRecords();
        List<StorageShelfRes> resList = new ArrayList<>();
        for (StorageShelfDo et : shelfDos) {
            StorageShelfRes res = new StorageShelfRes();
            BeanUtils.copyProperties(et, res);
            res.setTypeCN(StringsUtil.createI18Message(et.getType() == 1 ? SysConstant.StorageShelf_SMALL : SysConstant.StorageShelf_Big));
            res.setStatusCN(StringsUtil.createI18Message(et.getStatus() == 1 ? SysConstant.Enable : SysConstant.Unable));
            StorageDo storageDo = storageDao.selectById(et.getStorageId());
            if (null != storageDo) {
                res.setStorageCN(storageDo.getStorageName());
            }
            resList.add(res);
        }
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    @Override
    public void printBarCodePdf(Long id, HttpServletResponse response) {
        List<Map<String, String>> mapList = new ArrayList<>();
        List<String> codeStrList = new ArrayList<>();
        StorageShelfDo entityDo = dao.selectById(id);
        List<StoragePositionDo> list = positionDao.selectList(new QueryWrapper<StoragePositionDo>().eq("shelf_id", id));
        for (StoragePositionDo et : list) {
            codeStrList.add(et.getPositionName());
            Map<String, String> map = new HashMap<>();
            map.put("name", et.getPositionName());
//            map.put("name1", entityDo.getAreaName());
            mapList.add(map);
        }
        String name = entityDo.getAreaName() + "-" + TimeUtils.getCurrentDateFormat("HHmmss");
        BarCodePdfUtils.printBarCodePdf(mapList, 80, 50, codeStrList, name, response);
    }

    @Override
    public void printBarCodePdfOne(Long id, HttpServletResponse response) {
        StoragePositionDo positionDo = positionDao.selectById(id);
        StorageShelfDo shelfDo = dao.selectOne(new QueryWrapper<StorageShelfDo>().eq("id", positionDo.getShelfId()));
        List<Map<String, String>> mapList = new ArrayList<>();
        Map<String, String> map = new HashMap<>();
        map.put("name", positionDo.getPositionName());
//        map.put("name1", shelfDo.getAreaName());
        mapList.add(map);
        List<String> codeStrList = new ArrayList<>();
        codeStrList.add(positionDo.getPositionName());

        String name = shelfDo.getAreaName() + positionDo.getPositionName() + TimeUtils.getCurrentDateFormat("HHmmss");
        BarCodePdfUtils.printBarCodePdf(mapList, 80, 50, codeStrList, name, response);
    }

    @Override
    public int updateStatus(UpdateShelfStatusReq req, Long userId) {
        StorageShelfDo shelfDo = dao.selectById(req.getId());
        shelfDo.setStatus(req.getStatus());
        shelfDo.setUpdateBy(userId);
        shelfDo.setUpdateTime(new Date());
        return dao.updateById(shelfDo);
    }


    private IPage<StorageShelfDo> pageInit(Map<String, String> map) {
        IPage<StorageShelfDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<StorageShelfDo> queryBuild(Map<String, String> map) {
        QueryWrapper<StorageShelfDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("areaName"))) {
            wrapper.like("area_name", map.get("areaName"));
        }
        if (StringUtils.isNotBlank(map.get("storageId"))) {
            wrapper.eq("storage_id", map.get("storageId"));
        }
        wrapper.orderByAsc("sort");
        if (StringUtils.isNotBlank(map.get("companyId"))) {
            wrapper.eq("company_id", map.get("companyId"));
        }

        return wrapper;
    }

    @Override
    public PickupPreviewRes getPickupPreview(Long id) {
        StorageShelfDo et = dao.selectById(id);
        if (et == null) {
            throw new BizException(SysConstant.Error_Data_NotExist);
        }
        if (et.getGangway() == null || et.getShelfSort() == null || et.getFirstType() == null) {
            return null;
        }

        List<ShelfSortUpdateDto> list = positionDao.getSortPosList(id);
        if (et.getConfig() == 0) {
            //再去设置 库位拣货顺序
            return this.getPreviewResNew(et, list);
        }
        else {
            return this.getPreviewConfig(et, list);
        }
    }

    /**
     * 特殊货架的拣货预览
     * @return
     */
    @Override
    public PickupPreviewRes getPreviewConfig(StorageShelfDo et, List<ShelfSortUpdateDto> list) {
        List<StorageShelfGirdDo> shelfGirdDoList = storageShelfGirdDao.selectList(new LambdaQueryWrapper<StorageShelfGirdDo>().eq(StorageShelfGirdDo::getShelfId, et.getId()));
        //货架是单货架还是双货架
        Map<Integer, LineMsg> girdTypeMap = new HashMap<>();
        for (StorageShelfGirdDo storageShelfGirdDo : shelfGirdDoList) {
            girdTypeMap.put(storageShelfGirdDo.getLine(), new LineMsg(storageShelfGirdDo.getGirdType(), storageShelfGirdDo.getTopAisle(), storageShelfGirdDo.getBotAisle(), storageShelfGirdDo.getPickShelf()));
        }

        //获取最长货架，其余补齐
        Map<Integer, List<ShelfSortUpdateDto>> shelfListMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getShelfNumber));
        List<Integer> shelfList = new ArrayList<>(shelfListMap.keySet());
        int maxGird = 0;
        for (Integer shelf : shelfList) {
            List<ShelfSortUpdateDto> girdList = shelfListMap.get(shelf);
            //按照格子分类
            Map<Integer, List<ShelfSortUpdateDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
            if (maxGird < girdListMap.keySet().size()) {
                maxGird = girdListMap.keySet().size();
            }
        }


        //按照 line 去分
        Map<Integer, List<ShelfSortUpdateDto>> listMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getLine));
        List<Integer> lineList = new ArrayList<>(listMap.keySet());
        Integer firstType = et.getFirstType();
        if (et.getShelfType() == 0) { //逆序货架
            Collections.reverse(lineList);
        }
        List<PickupPreviewGridRes> sortList = new ArrayList<>();//按拣货顺序排
        List<List<PickupPreviewGridRes>> resListList = new ArrayList<>();//按 货架排序

        for (int lineIndex = 0; lineIndex < lineList.size(); lineIndex++) {
            List<PickupPreviewGridRes> girdRes = new ArrayList<>();

            List<PickupPreviewGridRes> aisleRes = new ArrayList<>(); //上下过道
            List<PickupPreviewGridRes> bottomRes = new ArrayList<>(); //上下过道
            Integer line = lineList.get(lineIndex);
            Integer pickShelf = girdTypeMap.get(line).getPickShelf();
            if (et.getShelfType() == 0) {
                //逆序货架
                if (pickShelf == 0) {
                    pickShelf = 1;
                }
                else {
                    pickShelf = 0;
                }
            }

            List<ShelfSortUpdateDto> lineShelf = listMap.get(line);
            //区分 左右
            Map<String, List<ShelfSortUpdateDto>> leftRightShelf = lineShelf.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getPosition));
            List<ShelfSortUpdateDto> leftGirdList = leftRightShelf.get("left");//左边
            //如果是 单货架 则在下面加一行过道
            //先添加货架格子
            if (leftGirdList == null || leftGirdList.size() == 0) {
                //则补空白格子
                //补齐格子
                for (int k = 0; k < maxGird; k++) {
                    girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
//                    aisleRes.add(this.getGirdRes(0, 0, "aisle",null, 0.0));
                    //左边没有货架 盒子参考右边
                    String girdType = leftRightShelf.get("right").get(0).getGirdType();
                    this.insertAisleWhenNull(et, girdType, line, girdTypeMap, aisleRes, bottomRes);
                }
            }
            else {
                //按照格子分类
                Map<Integer, List<ShelfSortUpdateDto>> girdListMap = leftGirdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
                Integer shelf = leftRightShelf.get("left").get(0).getShelfNumber();
                String girdType = leftRightShelf.get("left").get(0).getGirdType();
                this.insertAisleWhenNotNull(et, girdType, pickShelf, shelf, maxGird, "left", girdListMap, line, girdTypeMap, aisleRes, bottomRes);

                int i = 1;
                //在一开始 加上货架序号
                girdRes.add(this.getGirdRes(shelf, i++, "name", shelf, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.3));
                girdRes.add(this.getGirdRes(0, 0, "interval",null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));

                //补齐格子
                for (int k = girdListMap.keySet().size(); k < maxGird; k++) {
                    girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
                }

                //再去添加格子
                List<Integer> girdList = new ArrayList<>(girdListMap.keySet());
                Collections.reverse(girdList);
                for (Integer gird : girdList) {
                    PickupPreviewGridRes res = this.getGirdRes(shelf, i++, "normal", gird, girdListMap.get(gird).get(0).getRackSort() + 0.0);
                    //格子上的货物
                    Map<String, List<Item>> items = new HashMap<>();
                    for (ShelfSortUpdateDto dto : girdListMap.get(gird)) {
                        if (dto.getItems() == null || dto.getItems().get(dto.getPositionName()) == null) {
                            continue;
                        }
                        items.put(dto.getPositionName(), dto.getItems().get(dto.getPositionName()));
                    }
                    res.setItems(items);
                    girdRes.add(res);

                    sortList.add(this.getGirdRes(shelf, gird, "aisle", null, girdListMap.get(gird).get(0).getRackSort() + 0.0));
                }
                //单货架 line奇数 在上面 添加过道
            }

            //加两个过道格子
//                double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), , gird-1, shelf);
            PickupPreviewGridRes way = this.getGirdRes(0, 0, "between", null, 0);
            girdRes.add(way);
//                double rackSort2 = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, gird, shelf+1);
            PickupPreviewGridRes way1 = this.getGirdRes(0, 0, "between", null, 0);
            girdRes.add(way1);

            List<ShelfSortUpdateDto> rightGirdList = leftRightShelf.get("right");//右边边
            if (rightGirdList == null || rightGirdList.size() == 0) {
                //则补空白格子
                //补齐格子
                for (int k = 0; k < maxGird; k++) {
                    girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
//                    aisleRes.add(this.getGirdRes(0, 0, "aisle",null, 0.0));
                    //右边没有货架 格子参考左边
                    String girdType = leftRightShelf.get("left").get(0).getGirdType();
                    this.insertAisleWhenNull(et, girdType, line, girdTypeMap, aisleRes, bottomRes);
                }
            }
            else {
                //按照格子分类
                Map<Integer, List<ShelfSortUpdateDto>> girdListMap = rightGirdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
                Integer shelf = leftRightShelf.get("right").get(0).getShelfNumber();
                String girdType = leftRightShelf.get("right").get(0).getGirdType();
                this.insertAisleWhenNotNull(et, girdType, pickShelf, shelf, maxGird, "right", girdListMap, line, girdTypeMap, aisleRes, bottomRes);
                int i = 1;
                //再去添加格子
                for (Integer gird : girdListMap.keySet()) {
                    PickupPreviewGridRes res = this.getGirdRes(shelf, i++, "normal", gird, girdListMap.get(gird).get(0).getRackSort() + 0.0);
                    //todo 获取 货物信息
                    //格子上的货物
                    Map<String, List<Item>> items = new HashMap<>();
                    for (ShelfSortUpdateDto dto : girdListMap.get(gird)) {
                        if (dto.getItems() == null || dto.getItems().get(dto.getPositionName()) == null) {
                            continue;
                        }
                        items.put(dto.getPositionName(), dto.getItems().get(dto.getPositionName()));
                    }
                    res.setItems(items);
                    girdRes.add(res);

                    sortList.add(this.getGirdRes(shelf, gird, "aisle", null, girdListMap.get(gird).get(0).getRackSort() + 0.0));
                }
                //补齐格子
                for (int k = girdListMap.keySet().size(); k < maxGird; k++) {
                    girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
                }
                int y = 1;
                //在一开始 加上货架序号
                girdRes.add(this.getGirdRes(0, 0, "interval",null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));
                girdRes.add(this.getGirdRes(shelf, y++, "name", shelf, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.3));
            }
            if (aisleRes.size() > 0) {
                resListList.add(aisleRes);
            }
            resListList.add(girdRes);
            //加过道
            if (bottomRes.size() > 0) {
                resListList.add(bottomRes);
            }
        }


        PickupPreviewRes res = new PickupPreviewRes();
        BeanUtils.copyProperties(et, res);
        res.setPreview(resListList);
        sortList.sort(new Comparator<PickupPreviewGridRes>() {
            @Override
            public int compare(PickupPreviewGridRes o1, PickupPreviewGridRes o2) {
                if (o1.getRackSort() < o2.getRackSort()) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
        res.setSortList(sortList);
        return res;
    }


    public void insertAisleWhenNotNull(StorageShelfDo et, String girdType, Integer pickShelf, Integer shelf, int maxGird, String position, Set<Integer> girdListMapKeySet, Integer line, Map<Integer, LineMsg> girdTypeMap,  List<PickupPreviewGridRes> aisleRes, List<PickupPreviewGridRes> bottomRes) {
        if (et.getShelfType() == 1 || (et.getShelfType() == 0 && "single".equals(girdType))) {
            //顺序货架
            if (girdTypeMap.get(line).getTopAisle() == 1) {
                this.getAisle(aisleRes, pickShelf == 0 ? shelf : 0, maxGird, girdListMapKeySet, position);
            }
            if (girdTypeMap.get(line).getBotAisle() == 1) {
                this.getAisle(bottomRes, pickShelf == 1 ? shelf : 0, maxGird, girdListMapKeySet, position);
            }
        }
        else {
            if (girdTypeMap.get(line).getTopAisle() == 0) {
                this.getAisle(aisleRes, pickShelf == 0 ? shelf : 0, maxGird, girdListMapKeySet, position);
            }
            if (girdTypeMap.get(line).getBotAisle() == 0) {
                this.getAisle(bottomRes, pickShelf == 1 ? shelf : 0, maxGird, girdListMapKeySet, position);
            }
        }
    }


    public void insertAisleWhenNotNull(StorageShelfDo et, String girdType, Integer pickShelf, Integer shelf, int maxGird, String position, Map<Integer, List<ShelfSortUpdateDto>> girdListMap, Integer line, Map<Integer, LineMsg> girdTypeMap,  List<PickupPreviewGridRes> aisleRes, List<PickupPreviewGridRes> bottomRes) {
        this.insertAisleWhenNotNull(et, girdType, pickShelf, shelf, maxGird, position, girdListMap.keySet(), line,girdTypeMap, aisleRes, bottomRes);
    }

    /**
     * 当 左右货架只存在一个时 目前没用到
     */
    public void insertAisleWhenNull(StorageShelfDo et, String girdType, Integer line, Map<Integer, LineMsg> girdTypeMap,  List<PickupPreviewGridRes> aisleRes, List<PickupPreviewGridRes> bottomRes) {
        if (et.getShelfType() == 1 || (et.getShelfType() == 0 && "single".equals(girdType))) {
            //顺序货架
            if (girdTypeMap.get(line).getTopAisle() == 1) {
                aisleRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
            }
            if (girdTypeMap.get(line).getBotAisle() == 1) {
                bottomRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
            }
        }
        else {
            //逆序货架 当时double 时 反过来
            if (girdTypeMap.get(line).getTopAisle() == 0) {
                aisleRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
            }
            if (girdTypeMap.get(line).getBotAisle() == 0) {
                bottomRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
            }

        }
    }


    public void getAisle(List<PickupPreviewGridRes> aisleRes, int shelf, int maxGird, Set<Integer> girdListMapKeySet, String position) {
        if ("left".equals(position)) {
            //在一开始 加上货架序号
            aisleRes.add(this.getGirdRes(shelf, 0, "aisle", null, 0.0));
            aisleRes.add(this.getGirdRes(0, 0, "interval", null, 0.0));
            //补齐格子
            for (int k = girdListMapKeySet.size(); k < maxGird; k++) {
                aisleRes.add(this.getGirdRes(0, 0, "aisle", null, 0.0));
            }
        }
        //开始货架是双货架  奇数前面加一行 偶数后面加一行过道
        List<Integer> girdList = new ArrayList<>(girdListMapKeySet);
        if ("left".equals(position)) {
            Collections.reverse(girdList);
        }
        for (Integer gird : girdList) {
            aisleRes.add(this.getGirdRes(shelf, gird, "aisle",null, 0.0));
//            sortList.add(this.getGirdRes(shelf, gird, "aisle", null, girdListMap.get(gird).get(0).getRackSort() + 0.0));
        }

        if ("left".equals(position)) {
            //补两个过道格子
            PickupPreviewGridRes way = this.getGirdRes(0, 0, "aisle", null, 0);
            aisleRes.add(way);
//                double rackSort2 = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, gird, shelf+1);
            PickupPreviewGridRes way1 = this.getGirdRes(0, 0, "aisle", null, 0);
            aisleRes.add(way1);
        }

        if ("right".equals(position)) {
            //补齐格子
            for (int k = girdList.size(); k < maxGird; k++) {
                aisleRes.add(this.getGirdRes(0, 0, "aisle",null, 0.0));
            }
            //右边货架 在最后 加上货架序号
            aisleRes.add(this.getGirdRes(0, 0, "interval",null, 0.0));
            aisleRes.add(this.getGirdRes(shelf, 0, "aisle", null, 0.0));
        }
    }


    public void getAisle(List<PickupPreviewGridRes> aisleRes, int shelf, int maxGird, Map<Integer, List<ShelfSortUpdateDto>> girdListMap, String position) {
        this.getAisle(aisleRes, shelf, maxGird, girdListMap.keySet(), position);
    }




    @Override
    public PickupPreviewRes getPreviewResNew(StorageShelfDo et, List<ShelfSortUpdateDto> list) {
        //按照货架分类
        Map<Integer, List<ShelfSortUpdateDto>> shelfListMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getShelfNumber));

//        LinkedList<PickupPreviewGridRes> sortList = new LinkedList<>();
        List<PickupPreviewGridRes> sortList = new ArrayList<>();//按拣货顺序排
        List<List<PickupPreviewGridRes>> resListList = new ArrayList<>();//按 货架排序
        List<Integer> shelfList = new ArrayList<>(shelfListMap.keySet());
        Integer firstType = et.getFirstType();
        if (et.getShelfType() == 0) {
            Collections.reverse(shelfList);
        }
        //如果逆序拣货。重新判断起始货架 是单还是双货架
        et.setFirstType(this.jugFirstTypeNew(et, shelfList.size()));

        //获取最长货架，其余补齐
        int maxGird = 0;
        for (Integer shelf : shelfList) {
            List<ShelfSortUpdateDto> girdList = shelfListMap.get(shelf);
            //按照格子分类
            Map<Integer, List<ShelfSortUpdateDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));
            if (maxGird < girdListMap.keySet().size()) {
                maxGird = girdListMap.keySet().size();
            }
        }

        for (int j = 0; j < shelfList.size(); j++) {
            Integer shelf = shelfList.get(j);
            List<ShelfSortUpdateDto> girdList = shelfListMap.get(shelf);
            //按照格子分类
            Map<Integer, List<ShelfSortUpdateDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));

            //加过道
            if ((et.getFirstType() == 1 && (j+1) % 2 == 1) || (et.getFirstType() == 0 && (j+1) % 2 == 0)) {
                //开始货架是双货架  奇数前面加一行 偶数后面加一行过道
                //加过道
                this.getAisle(et, j, shelf, maxGird, girdListMap, sortList, resListList);
            }

            //加货架格子
            int i = 1;
            List<PickupPreviewGridRes> girdRes = new ArrayList<>();
            //在一开始 加上货架序号
            girdRes.add(this.getGirdRes(shelf, i++, "name", girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getShelfNumber(), girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.3));
            girdRes.add(this.getGirdRes(0, 0, "interval",null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));

            if (et.getGangway() == 0) {
                //过道在左侧
                double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, new ArrayList<>(girdListMap.keySet()).get(0), shelf);
                PickupPreviewGridRes way = this.getGirdRes(shelf, i++, "left", null, rackSort);

                girdRes.add(way);
            }
            for (Integer gird : girdListMap.keySet()) {
                String type = "";
                if (et.getGangway() == 3) {
                    //3过道在格子上
                    if (et.getBeginGrid() <= gird && et.getEndGrid() >= gird) {
                        type = ("on");
                    } else {
                        type = ("normal");
                    }
                } else if (et.getGangway() == 4) {
                    //4 过道在格子之间
                    if (et.getEndGrid().equals(gird)) {
                        //加两个过道格子
                        double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, gird-1, shelf);
                        PickupPreviewGridRes way = this.getGirdRes(shelf, i++, "between", null, rackSort);
                        girdRes.add(way);
                        double rackSort2 = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, gird, shelf+1);
                        PickupPreviewGridRes way1 = this.getGirdRes(shelf, i++, "between", null, rackSort2);
                        girdRes.add(way1);
                    }
                    type  = ("normal");
                } else {
                    type = ("normal");
                }
                PickupPreviewGridRes res = this.getGirdRes(shelf, i++, type, gird, girdListMap.get(gird).get(0).getRackSort() + 0.0);
                //格子上的货物
                Map<String, List<Item>> items = new HashMap<>();
                for (ShelfSortUpdateDto dto : girdListMap.get(gird)) {
                    if (dto.getItems() == null || dto.getItems().get(dto.getPositionName()) == null) {
                        continue;
                    }
                    items.put(dto.getPositionName(), dto.getItems().get(dto.getPositionName()));
                }
                res.setItems(items);
                girdRes.add(res);
            }

            //补齐格子
            for (int k = girdListMap.keySet().size(); k < maxGird; k++) {
                girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
            }

            if (et.getGangway() == 1) {
                double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, girdListMap.keySet().size() - 1, shelf);
                //过道在右侧
                PickupPreviewGridRes way = this.getGirdRes(shelf, i, "right", null, rackSort);
                girdRes.add(way);
            }
            resListList.add(girdRes);
            //加过道
            if ((et.getFirstType() == 1 && (j+1) % 2 == 0) || et.getFirstType() == 0 && (j+1) % 2 == 1) {
                this.getAisle(et, j, shelf, maxGird, girdListMap, sortList, resListList);
            }
        }


        PickupPreviewRes res = new PickupPreviewRes();
        BeanUtils.copyProperties(et, res);
        res.setPreview(resListList);
        sortList.sort(new Comparator<PickupPreviewGridRes>() {
            @Override
            public int compare(PickupPreviewGridRes o1, PickupPreviewGridRes o2) {
                if (o1.getRackSort() < o2.getRackSort()) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
        res.setSortList(sortList);
        res.setFirstType(firstType);
        return res;
    }


    public void getAisle(StorageShelfDo et, int j, int shelf, int maxGird, Map<Integer, List<ShelfSortUpdateDto>> girdListMap, List<PickupPreviewGridRes> sortList, List<List<PickupPreviewGridRes>> resListList) {
        //加过道
        //开始货架是双货架  奇数前面加一行 偶数后面加一行过道
        int iz = 1;
        List<PickupPreviewGridRes> aisleRes = new ArrayList<>();
        //在一开始 加上货架序号
//        this.getRackSort(et.getFirstType(), girdListMap, new ArrayList<>(girdListMap.keySet()).get(0), j);
        aisleRes.add(this.getGirdRes(shelf, iz++, "aisle", null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));
        aisleRes.add(this.getGirdRes(0, 0, "interval",null, 0.0));
        if (et.getGangway() == 0) {
            //过道在左侧
            double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, new ArrayList<>(girdListMap.keySet()).get(0), shelf);
            PickupPreviewGridRes way = this.getGirdRes(shelf, iz++, "aisle", null, rackSort);
            aisleRes.add(way);
            sortList.add(way);
        }
        for (Integer gird : girdListMap.keySet()) {
            if (et.getGangway() == 4) {
                //4 过道在格子之间
                if (et.getEndGrid().equals(gird)) {
                    //加两个过道格子
                    double rackSort = this.getRackSort(et.getFirstType(),  et.getShelfType(), et.getShelfSort(), girdListMap, gird - 1, shelf);
                    PickupPreviewGridRes way = this.getGirdRes(shelf, iz++, "aisle", null, rackSort);
                    aisleRes.add(way);
                    sortList.add(way);
                    double rackSort1 = this.getRackSort(et.getFirstType(), et.getShelfType(), et.getShelfSort(), girdListMap, gird, shelf+1);
                    PickupPreviewGridRes way1 = this.getGirdRes(shelf, iz++, "aisle", null, rackSort1);
                    aisleRes.add(way1);
                    sortList.add(way1);
                }
            }
            PickupPreviewGridRes res = this.getGirdRes(shelf, iz++, "aisle", null, girdListMap.get(gird).get(0).getRackSort() + 0.0);
            aisleRes.add(res);
            sortList.add(res);
        }
        //补齐格子
        for (int k = girdListMap.keySet().size(); k < maxGird; k++) {
            aisleRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
//            sortList.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
        }
        if (et.getGangway() == 1) {
            //过道在右侧
            double rackSort = this.getRackSort(et.getFirstType(), et.getShelfType(), et.getShelfSort(), girdListMap, new ArrayList<>(girdListMap.keySet()).get(girdListMap.keySet().size() - 1), shelf);
            PickupPreviewGridRes way = this.getGirdRes(shelf, iz, "aisle", null, rackSort);
            aisleRes.add(way);
            sortList.add(way);
        }
        resListList.add(aisleRes);
    }

    public PickupPreviewGridRes getGirdRes(int x, int y, String type, Integer gird, double rackSort) {
        PickupPreviewGridRes girdName = new PickupPreviewGridRes();
        girdName.setX(x);
        girdName.setY(y);
        girdName.setType(type);
        girdName.setGird(gird);
        girdName.setRackSort(rackSort);
        return girdName;
    }


    public double getRackSort(Integer firstType, Integer shelfType, Integer shelfSort, Map<Integer, List<ShelfSortUpdateDto>> girdListMap, int gird, int j) {
        if ((shelfType == 1 && shelfSort == 1) || (shelfType == 0 && shelfSort == 0)) {//货架拣货顺序， 0 顺序 1逆序
            j += 1;
        }
        double rackSort = 0;
        if (firstType == 0) {
            //单货架
            if (j % 2 == 0) {
                rackSort = (girdListMap.get(gird).get(0).getRackSort() + 0.1);
            } else {
                rackSort = (girdListMap.get(gird).get(0).getRackSort() - 0.1);
            }

        } else {
            //双货架
            if (j % 2 == 0) {
                rackSort = (girdListMap.get(gird).get(0).getRackSort() - 0.1);
            } else {
                rackSort = (girdListMap.get(gird).get(0).getRackSort() + 0.1);
            }
        }
        return rackSort;
    }


    @Override
    public PickupPreviewRes getPreviewRes(StorageShelfDo et, List<ShelfSortUpdateDto> list) {
        //按照货架分类
        Map<Integer, List<ShelfSortUpdateDto>> shelfListMap = list.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getShelfNumber));

        List<PickupPreviewGridRes> sortList = new ArrayList<>();//按拣货顺序排
        List<List<PickupPreviewGridRes>> resListList = new ArrayList<>();//按 货架排序
        List<Integer> shelfList = new ArrayList<>(shelfListMap.keySet());
        Integer firstType = et.getFirstType();
        if (et.getShelfSort() == 1) {
            Collections.reverse(shelfList);
            //如果逆序拣货。重新判断起始货架 是单还是双货架
            int shelfCount = shelfList.size();
            if (et.getFirstType() == 0) {
                shelfCount -= 1;
            }
            if (shelfCount % 2 == 0) {
                //说明是双货架
                et.setFirstType(1);
            }
            else {
                //单货架
                et.setFirstType(0);
            }
        }
        //如果逆序拣货。重新判断起始货架 是单还是双货架
        et.setFirstType(this.jugFirstType(et, shelfList.size()));

        for (int j = 0; j < shelfList.size(); j++) {
            Integer shelf = shelfList.get(j);
            List<ShelfSortUpdateDto> girdList = shelfListMap.get(shelf);
            //按照格子分类
            Map<Integer, List<ShelfSortUpdateDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(ShelfSortUpdateDto::getGridNumber));

            int i = 1;
            List<PickupPreviewGridRes> girdRes = new ArrayList<>();
            if (et.getGangway() == 0) {
                //过道在左侧
                PickupPreviewGridRes way = new PickupPreviewGridRes();
                way.setX(shelf);
                way.setY(i++);
                way.setType("left");
                if (et.getFirstType() == 0) {
                    //单货架
                    if (j % 2 == 0) {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.1);
                    } else {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() + 0.1);
                    }

                } else {
                    //双货架
                    if (j % 2 == 0) {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() + 0.1);
                    } else {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.1);
                    }
                }
                girdRes.add(way);
                sortList.add(way);
            }
            for (Integer gird : girdListMap.keySet()) {
                PickupPreviewGridRes res = new PickupPreviewGridRes();
                if (et.getGangway() == 3) {
                    //3过道在格子上
                    if (et.getBeginGrid() <= gird && et.getEndGrid() >= gird) {
                        res.setType("on");
                    } else {
                        res.setType("normal");
                    }
                } else if (et.getGangway() == 4) {
                    //4 过道在格子之间
                    if (et.getEndGrid().equals(gird)) {
                        //加两个过道格子
                        PickupPreviewGridRes way = new PickupPreviewGridRes();
                        way.setX(shelf);
                        way.setY(i++);
                        way.setType("between");
                        if (et.getFirstType() == 0) {
                            //单货架
                            if (j % 2 == 0) {
                                way.setRackSort(girdListMap.get(gird - 1).get(0).getRackSort() - 0.1);
                            } else {
                                way.setRackSort(girdListMap.get(gird - 1).get(0).getRackSort() + 0.1);
                            }

                        } else {
                            //双货架
                            if (j % 2 == 0) {
                                way.setRackSort(girdListMap.get(gird - 1).get(0).getRackSort() + 0.1);
                            } else {
                                way.setRackSort(girdListMap.get(gird - 1).get(0).getRackSort() - 0.1);
                            }
                        }

                        girdRes.add(way);
                        sortList.add(way);

                        PickupPreviewGridRes way1 = new PickupPreviewGridRes();
                        way1.setX(shelf);
                        way1.setY(i++);
                        way1.setType("between");
                        if (et.getFirstType() == 0) {
                            //单货架
                            if (j % 2 == 0) {
                                way1.setRackSort(girdListMap.get(gird).get(0).getRackSort() + 0.1);
                            } else {
                                way1.setRackSort(girdListMap.get(gird).get(0).getRackSort() - 0.1);
                            }

                        } else {
                            //双货架
                            if (j % 2 == 0) {
                                way1.setRackSort(girdListMap.get(gird).get(0).getRackSort() - 0.1);
                            } else {
                                way1.setRackSort(girdListMap.get(gird).get(0).getRackSort() + 0.1);
                            }
                        }

                        girdRes.add(way1);
                        sortList.add(way1);
                    }
                    res.setType("normal");
                } else {
                    res.setType("normal");
                }
                res.setGird(gird);
                res.setX(shelf);
                res.setY(i++);
                res.setRackSort(girdListMap.get(gird).get(0).getRackSort() + 0.0);
                //格子上的货物
                Map<String, List<Item>> items = new HashMap<>();
                for (ShelfSortUpdateDto dto : girdListMap.get(gird)) {
                    if (dto.getItems() == null || dto.getItems().get(dto.getPositionName()) == null) {
                        continue;
                    }
                    items.put(dto.getPositionName(), dto.getItems().get(dto.getPositionName()));
                }
                res.setItems(items);
                girdRes.add(res);
                sortList.add(res);
            }
            if (et.getGangway() == 1) {
                //过道在右侧
                PickupPreviewGridRes way = new PickupPreviewGridRes();
                way.setX(shelf);
                way.setY(i);
                way.setType("right");

                if (et.getFirstType() == 0) {
                    //单货架
                    if (j % 2 == 0) {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(girdListMap.keySet().size() - 1)).get(0).getRackSort() - 0.1);
                    } else {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(girdListMap.keySet().size() - 1)).get(0).getRackSort() + 0.1);
                    }

                } else {
                    //双货架
                    if (j % 2 == 0) {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(girdListMap.keySet().size() - 1)).get(0).getRackSort() + 0.1);
                    } else {
                        way.setRackSort(girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(girdListMap.keySet().size() - 1)).get(0).getRackSort() - 0.1);
                    }
                }
                girdRes.add(way);
                sortList.add(way);

            }
            resListList.add(girdRes);
        }


        PickupPreviewRes res = new PickupPreviewRes();
        BeanUtils.copyProperties(et, res);
        res.setPreview(resListList);
        sortList.sort(new Comparator<PickupPreviewGridRes>() {
            @Override
            public int compare(PickupPreviewGridRes o1, PickupPreviewGridRes o2) {
                if (o1.getRackSort() < o2.getRackSort()) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
        res.setSortList(sortList);
        res.setFirstType(firstType);
        return res;
    }


    //每月月初刷新 库存
    @Override
    public void refreshOutVolResListRedis() {
        Map<String, String> param = new HashMap<>();
        List<PositionOutVolRes> outVolResList = productStockRackDao.getPositionOutVolResList(param);
        redisTemplate.opsForValue().set(redisStorageOutVolResList, JSON.toJSONString(outVolResList), 60 * 60 * 12, TimeUnit.SECONDS);
    }

    private final String redisStorageOutVolResList = "StorageOutVolResList_";

    /**
     * 整个仓库的 容量预览图
     */
    @Override
    public StorageVolumePreviewRes storageVolumePreview(Long storageId) {
        //先获取仓库下所有的库存，按库位分
        Map<String, String> param = new HashMap<>();
        param.put("type", "1");//只看有库存的库位
        param.put("storageId", storageId + "");
        param.put("notDefault", "1");//不看默认库位
        List<ProductStockDetailDto> stockList = productStockRackDao.getStockList(param);
        Map<Long, List<ProductStockDetailDto>> stockListMap = stockList.stream().collect(Collectors.groupingBy(ProductStockDetailDto::getRackId));

        //获取上月仓库 出库体积 按库位分
        List<PositionOutVolRes> outVolResList;
        Object redisRes = redisTemplate.opsForValue().get(redisStorageOutVolResList);
        if (redisRes != null) {
            outVolResList = JSONArray.parseArray(redisRes.toString(), PositionOutVolRes.class);
        } else {
            Map<String, String> map = new HashMap<>();
            outVolResList = productStockRackDao.getPositionOutVolResList(map);
            redisTemplate.opsForValue().set(redisStorageOutVolResList, JSON.toJSONString(outVolResList), 60 * 60 * 12, TimeUnit.SECONDS);
        }
        Map<Long, List<PositionOutVolRes>> outVolResListMap = outVolResList.stream().collect(Collectors.groupingBy(PositionOutVolRes::getRackId));


        List<StoragePreviewDto> list = positionDao.getPositionByStorageId(storageId, null);

        //按货架 区分
        Map<String, List<StoragePreviewDto>> previewMapList = list.stream().collect(Collectors.groupingBy(i -> i.getShelfId() + "-" + i.getShelfSort()));
        Set<String> keySet = previewMapList.keySet();
        keySet.stream().sorted(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                if ("null".equals(o1.split("-")[1]) && !"null".equals(o2.split("-")[2])) {
                    return 1;
                } else if ("null".equals(o2.split("-")[2]) && !"null".equals(o2.split("-")[1])) {
                    return -1;
                } else {
                    return Long.parseLong(o1.split("-")[1]) > Long.parseLong(o2.split("-")[1]) ? 1 : -1;
                }
            }
        });

        List<StoragePreviewRes> previewResList = new ArrayList<>();
        for (String key : keySet) {//key是 shelfId
            StorageShelfDo et = dao.selectById(key);
            if (et == null) {
                continue;
            }
            if (et.getConfig() == 0) {
                StoragePreviewRes previewRes = new StoragePreviewRes();
                BeanUtils.copyProperties(et, previewRes);
                if (et.getGangway() == null || et.getShelfSort() == null || et.getFirstType() == null) {
                    throw new BizException(SysConstant.Shelf_Error_Sort, et.getShelfName());
                }
                //次数集合 是一个大区下的所有库位
                List<StoragePreviewDto> keyList = previewMapList.get(key);
                //按照货架分类
                Map<Integer, List<StoragePreviewDto>> shelfListMap = keyList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getShelfNumber));

                List<Integer> shelfList = new ArrayList<>(shelfListMap.keySet());
                if (et.getShelfType() == 0) {
                    Collections.reverse(shelfList);
                }
                List<List<PickupPreviewGridRes>> resListList = new ArrayList<>();//按 货架排序
                for (Integer shelf : shelfList) {
                    //按格子分
                    List<StoragePreviewDto> girdList = shelfListMap.get(shelf);
                    //按照格子分类
                    Map<Integer, List<StoragePreviewDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getGridNumber));

                    //按层分
                    List<Integer> girdNumberList = new ArrayList<>(girdListMap.keySet());
                    int i = 1;
                    List<PickupPreviewGridRes> girdRes = new ArrayList<>();

                    if (et.getGangway() == 0) {
                        for (int o = 0; o < girdListMap.get(girdNumberList.get(0)).size(); o++) {
                            //过道在左侧
                            PickupPreviewGridRes way = new PickupPreviewGridRes();
                            way.setX(-1);
                            way.setY(o);
                            way.setType("left");
                            girdRes.add(way);
                        }
                    }

                    int gg = 0;//格子位数包括过道
                    for (Integer gird : girdNumberList) {
                        List<StoragePreviewDto> tierList = girdListMap.get(gird);
                        if (et.getGangway() == 4 && et.getEndGrid().equals(gird)) {//4 过道在格子之间
                            for (int j = 0; j < 2; j++) {
                                int tt = 0;
                                for (int t = 0; t < tierList.size(); t++) {
                                    //加两个过道格子
                                    PickupPreviewGridRes way = new PickupPreviewGridRes();
                                    way.setX(gg);
                                    way.setY(tt++);
                                    way.setType("between");
                                    girdRes.add(way);
                                }
                                gg++;
                            }
                        }

                        int tt = 0;
                        for (int j = tierList.size(); j < et.getTierNum(); j++) {
                            //加两个过道格子
                            PickupPreviewGridRes way = new PickupPreviewGridRes();
                            way.setX(gg);
                            way.setY(tt++);
                            way.setType("between");
                            girdRes.add(way);
                        }
                        for (int t = 0; t < tierList.size(); t++) {
                            StoragePreviewDto tirePreviewDto = tierList.get(t);
                            PickupPreviewGridRes res = new PickupPreviewGridRes();
                            BeanUtils.copyProperties(tirePreviewDto, res);
                            if (et.getGangway() == 3) {
                                //3过道在格子上
                                if (et.getBeginGrid() <= gird && et.getEndGrid() >= gird && tierList.size() == et.getTierNum()) {
                                    //第三层 是库位， 1,2层是过道
                                    res.setType("on");
                                } else {
                                    res.setType("normal");
                                }
                            } else if (et.getGangway() == 4) {
                                //4 过道在格子之间
                                res.setType("normal");
                            } else {
                                res.setType("normal");
                            }
                            res.setGird(gird);
                            res.setX(gg);
                            res.setY(tt++);
                            res.setPositionName(tirePreviewDto.getPositionName());
                            res.setTierMsg(et.getShelfName() + et.getShelfNum() + "-" + (t + 1));
//                        res.setRackSort(girdListMap.get(gird).get(0).getRackSort()+0.0);
                            //格子上的货物
                            if (stockListMap.get(tirePreviewDto.getId()) != null) {
                                Map<String, List<Item>> items = new HashMap<>();
                                List<Item> itemList = new ArrayList<>();
                                for (ProductStockDetailDto detailDto : stockListMap.get(tirePreviewDto.getId())) {
                                    Item item = new Item(detailDto.getCommoditySku(), detailDto.getGoodQuantity() + detailDto.getBadQuantity() + detailDto.getGoodLockQuantity() + detailDto.getBadLockQuantity());
                                    itemList.add(item);
                                }
                                items.put(tirePreviewDto.getPositionName(), itemList);
                                res.setItems(items);
                            }

                            //月库位利用率 = 月出货总体积/库位总体积
                            if (outVolResListMap.get(tirePreviewDto.getId()) != null && tirePreviewDto.getStockCapacity() != 0) {
                                res.setMonthRackUseRatio(MathUtils.numberFormat(outVolResListMap.get(tirePreviewDto.getId()).get(0).getOutVolume() / tirePreviewDto.getStockCapacity() * 100 + "", 2));
                            } else {
                                res.setMonthRackUseRatio("0");
                            }

                            girdRes.add(res);
                        }
                        gg++;
                    }

                    if (et.getGangway() == 1) {
                        for (int o = 0; o < girdListMap.get(girdNumberList.get(0)).size(); o++) {
                            //过道在右侧
                            PickupPreviewGridRes way = new PickupPreviewGridRes();
                            way.setX(gg);
                            way.setY(o);
                            way.setType("right");
                            girdRes.add(way);
                        }
                    }
                    resListList.add(girdRes);
                }
                previewRes.setPreview(resListList);
                previewResList.add(previewRes);
            }
            else {
                StoragePreviewRes previewRes = new StoragePreviewRes();
                BeanUtils.copyProperties(et, previewRes);
//                //特殊类型货架
                List<StorageShelfGirdDo> shelfGirdDoList = storageShelfGirdDao.selectList(new LambdaQueryWrapper<StorageShelfGirdDo>().eq(StorageShelfGirdDo::getShelfId, et.getId()));
                //货架是单货架还是双货架
                Map<Integer, LineMsg> girdTypeMap = new HashMap<>();
                for (StorageShelfGirdDo storageShelfGirdDo : shelfGirdDoList) {
                    girdTypeMap.put(storageShelfGirdDo.getLine(), new LineMsg(storageShelfGirdDo.getGirdType(), storageShelfGirdDo.getTopAisle(), storageShelfGirdDo.getBotAisle(), storageShelfGirdDo.getPickShelf()));
                }
                previewRes.setMsg(girdTypeMap);

                //集合 是一货架下的所有库位
                List<StoragePreviewDto> keyList = previewMapList.get(key);

                //获取最长货架，其余补齐
                Map<Integer, List<StoragePreviewDto>> shelfListMap = keyList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getShelfNumber));
                List<Integer> shelfList = new ArrayList<>(shelfListMap.keySet());
                int maxGird = 0;
                for (Integer shelf : shelfList) {
                    List<StoragePreviewDto> girdList = shelfListMap.get(shelf);
                    //按照格子分类
                    Map<Integer, List<StoragePreviewDto>> girdListMap = girdList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getGridNumber));
                    if (maxGird < girdListMap.keySet().size()) {
                        maxGird = girdListMap.keySet().size();
                    }
                }
                //按照 line 去分
                Map<Integer, List<StoragePreviewDto>> listMap = list.stream().filter(i -> i.getLine() != null).collect(Collectors.groupingBy(StoragePreviewDto::getLine));
                List<Integer> lineList = new ArrayList<>(listMap.keySet());
                if (et.getShelfType() == 0) { //逆序货架
                    Collections.reverse(lineList);
                }
                List<List<PickupPreviewGridRes>> resListList = new ArrayList<>();//按 货架排序

                for (int lineIndex = 0; lineIndex < lineList.size(); lineIndex++) {
                    List<PickupPreviewGridRes> girdRes = new ArrayList<>();

                    List<PickupPreviewGridRes> aisleRes = new ArrayList<>(); //上下过道
                    List<PickupPreviewGridRes> bottomRes = new ArrayList<>(); //上下过道
                    Integer line = lineList.get(lineIndex);
                    List<StoragePreviewDto> lineShelf = listMap.get(line);
                    //区分 左右
                    Map<String, List<StoragePreviewDto>> leftRightShelf = lineShelf.stream().collect(Collectors.groupingBy(StoragePreviewDto::getPosition));
                    List<StoragePreviewDto> leftGirdList = leftRightShelf.get("left");//左边
                    //如果是 单货架 则在下面加一行过道
                    //先添加货架格子
                    int gg = 0;
                    if (leftGirdList == null || leftGirdList.size() == 0) {
                        //则补空白格子
                        //补齐格子
                        for (int k = 0; k < maxGird; k++) {
                            girdRes.add(this.getGirdRes(gg++, 0, "buQi",null, 0.0));
                            aisleRes.add(this.getGirdRes(gg++, 0, "aisle",null, 0.0));
                        }
                    }
                    else {
                        //按照格子分类
                        Map<Integer, List<StoragePreviewDto>> girdListMap = leftGirdList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getGridNumber));
                        Integer shelf = leftRightShelf.get("left").get(0).getShelfNumber();
                        String girdType = leftRightShelf.get("left").get(0).getGirdType();

//                        this.insertAisleWhenNotNull(et, girdType, pickShelf, shelf, maxGird, "left", girdListMap.keySet(), line, girdTypeMap, aisleRes, bottomRes);

                        //在一开始 加上货架序号
                        for (int t = 0; t < et.getTierNum(); t++) {
                            girdRes.add(this.getGirdRes(gg, t, "name", shelf, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.3));
                        }
                        gg++;

                        for (int t = 0; t < et.getTierNum(); t++) {
                            girdRes.add(this.getGirdRes(gg, t, "interval",null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));
                        }
                        gg++;
                        List<Integer> girdList = new ArrayList<>(girdListMap.keySet());
                        Collections.reverse(girdList);

                        //补齐格子
                        for (int k = girdListMap.keySet().size(); k < maxGird; k++) {

                                for (int t = 0; t < et.getTierNum(); t++) {
                                    //加两个过道格子
                                    PickupPreviewGridRes way = new PickupPreviewGridRes();
                                    way.setX(gg);
                                    way.setY(t);
                                    way.setType("buQi");
                                    girdRes.add(way);
                                }
                                gg++;

                        }

                        for (Integer gird : girdList) {
                            List<StoragePreviewDto> tierList = girdListMap.get(gird);
                            int tt = 0;
                            for (int j = tierList.size(); j < et.getTierNum(); j++) {
                                //如果这格子 得层数没有 货架指定层数 则补齐
                                PickupPreviewGridRes way = new PickupPreviewGridRes();
                                way.setX(gg);
                                way.setY(tt++);
                                way.setType("buQi");
                                girdRes.add(way);
                            }
                            for (int t = 0; t < tierList.size(); t++) {
                                StoragePreviewDto tirePreviewDto = tierList.get(t);
                                PickupPreviewGridRes res = new PickupPreviewGridRes();
                                BeanUtils.copyProperties(tirePreviewDto, res);
                                res.setGird(gird);
                                res.setX(gg);
                                res.setY(tt++);
                                res.setType("normal");
                                res.setPositionName(tirePreviewDto.getPositionName());
                                res.setTierMsg(et.getShelfName() + et.getShelfNum() + "-" + (t + 1));
                                //格子上的货物
                                if (stockListMap.get(tirePreviewDto.getId()) != null) {
                                    Map<String, List<Item>> items = new HashMap<>();
                                    List<Item> itemList = new ArrayList<>();
                                    for (ProductStockDetailDto detailDto : stockListMap.get(tirePreviewDto.getId())) {
                                        Item item = new Item(detailDto.getCommoditySku(), detailDto.getGoodQuantity() + detailDto.getBadQuantity() + detailDto.getGoodLockQuantity() + detailDto.getBadLockQuantity());
                                        itemList.add(item);
                                    }
                                    items.put(tirePreviewDto.getPositionName(), itemList);
                                    res.setItems(items);
                                }

                                //月库位利用率 = 月出货总体积/库位总体积
                                if (outVolResListMap.get(tirePreviewDto.getId()) != null && tirePreviewDto.getStockCapacity() != 0) {
                                    res.setMonthRackUseRatio(MathUtils.numberFormat(outVolResListMap.get(tirePreviewDto.getId()).get(0).getOutVolume() / tirePreviewDto.getStockCapacity() * 100 + "", 2));
                                } else {
                                    res.setMonthRackUseRatio("0");
                                }

                                girdRes.add(res);
                            }
                            gg++;
                        }
                    }
                    for (int j = 0; j < 2; j++) {
                        for (int t = 0; t < et.getTierNum(); t++) {
                            //加两个过道格子
                            PickupPreviewGridRes way = this.getGirdRes(gg, t, "between", null, 0);
                            girdRes.add(way);
                        }
                        gg++;
                    }

                    List<StoragePreviewDto> rightGirdList = leftRightShelf.get("right");//右边边
                    if (rightGirdList == null || rightGirdList.size() == 0) {
                        //则补空白格子
                        //补齐格子
                        for (int k = 0; k < maxGird; k++) {
                            girdRes.add(this.getGirdRes(0, 0, "buQi",null, 0.0));
                        }
                    }
                    else {
                        //按照格子分类
                        Map<Integer, List<StoragePreviewDto>> girdListMap = rightGirdList.stream().collect(Collectors.groupingBy(StoragePreviewDto::getGridNumber));
                        Integer shelf = leftRightShelf.get("right").get(0).getShelfNumber();
                        String girdType = leftRightShelf.get("left").get(0).getGirdType();

                        //开始货架是双货架  奇数前面加一行 偶数后面加一行过道
//                        this.insertAisleWhenNotNull(et, girdType, pickShelf, shelf, maxGird, "right", girdListMap.keySet(), line, girdTypeMap, aisleRes, bottomRes);

                        List<Integer> girdList = new ArrayList<>(girdListMap.keySet());
                        for (Integer gird : girdList) {
                            List<StoragePreviewDto> tierList = girdListMap.get(gird);
                            int tt = 0;
                            for (int j = tierList.size(); j < et.getTierNum(); j++) {
                                //如果这格子 得层数没有 货架指定层数 则补齐
                                PickupPreviewGridRes way = new PickupPreviewGridRes();
                                way.setX(gg);
                                way.setY(tt++);
                                way.setType("buQi");
                                girdRes.add(way);
                            }
                            for (int t = 0; t < tierList.size(); t++) {
                                StoragePreviewDto tirePreviewDto = tierList.get(t);
                                PickupPreviewGridRes res = new PickupPreviewGridRes();
                                BeanUtils.copyProperties(tirePreviewDto, res);
                                res.setGird(gird);
                                res.setX(gg);
                                res.setType("normal");
                                res.setY(tt++);
                                res.setPositionName(tirePreviewDto.getPositionName());
                                res.setTierMsg(et.getShelfName() + et.getShelfNum() + "-" + (t + 1));
                                //格子上的货物
                                if (stockListMap.get(tirePreviewDto.getId()) != null) {
                                    Map<String, List<Item>> items = new HashMap<>();
                                    List<Item> itemList = new ArrayList<>();
                                    for (ProductStockDetailDto detailDto : stockListMap.get(tirePreviewDto.getId())) {
                                        Item item = new Item(detailDto.getCommoditySku(), detailDto.getGoodQuantity() + detailDto.getBadQuantity() + detailDto.getGoodLockQuantity() + detailDto.getBadLockQuantity());
                                        itemList.add(item);
                                    }
                                    items.put(tirePreviewDto.getPositionName(), itemList);
                                    res.setItems(items);
                                }

                                //月库位利用率 = 月出货总体积/库位总体积
                                if (outVolResListMap.get(tirePreviewDto.getId()) != null && tirePreviewDto.getStockCapacity() != 0) {
                                    res.setMonthRackUseRatio(MathUtils.numberFormat(outVolResListMap.get(tirePreviewDto.getId()).get(0).getOutVolume() / tirePreviewDto.getStockCapacity() * 100 + "", 2));
                                } else {
                                    res.setMonthRackUseRatio("0");
                                }

                                girdRes.add(res);
                            }
                            gg++;
                        }

                        //补齐格子
                        for (int k = girdListMap.keySet().size(); k < maxGird; k++) {
                                for (int t = 0; t < et.getTierNum(); t++) {
                                    //加两个过道格子
                                    PickupPreviewGridRes way = new PickupPreviewGridRes();
                                    way.setX(gg);
                                    way.setY(t);
                                    way.setType("buQi");
                                    girdRes.add(way);
                                }
                                gg++;

                        }
                        int y = 0;
                        //在一开始 加上货架序号
                        for (int t = 0; t < et.getTierNum(); t++) {
                            girdRes.add(this.getGirdRes(gg, t, "interval",null, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.2));
                        }
                        gg++;
                        for (int t = 0; t < et.getTierNum(); t++) {
                            girdRes.add(this.getGirdRes(gg, t, "name", shelf, girdListMap.get(new ArrayList<>(girdListMap.keySet()).get(0)).get(0).getRackSort() - 0.3));
                        }
                        gg++;
                    }
                    if (aisleRes.size() > 0) {
                        resListList.add(aisleRes);
                    }
                    resListList.add(girdRes);
                    //加过道
                    if (bottomRes.size() > 0) {
                        resListList.add(bottomRes);
                    }
                }
                previewRes.setPreview(resListList);
                previewResList.add(previewRes);

            }
        }

        //获取仓库梯度配置情况
        List<StorageShowRuleDo> ruleDoList = storageShowRuleDao.selectList(new LambdaQueryWrapper<StorageShowRuleDo>()
                .eq(StorageShowRuleDo::getStorageId, storageId));

        List<StorageShowRuleRes> ruleResList = new ArrayList<>();
        if (ruleDoList.size() == 0) {
            ruleResList.add(new StorageShowRuleRes(0, 0, "#C0C0C0"));
            ruleResList.add(new StorageShowRuleRes(0, 30, "#8FBC8F"));
            ruleResList.add(new StorageShowRuleRes(30, 60, "#00FF00"));
            ruleResList.add(new StorageShowRuleRes(60, 80, "#BC8F8F"));
            ruleResList.add(new StorageShowRuleRes(80, null, "#FF0000"));
        } else {
            for (StorageShowRuleDo et : ruleDoList) {
                ruleResList.add(new StorageShowRuleRes(et.getBegin(), et.getEnd(), et.getColor()));
            }
        }


        StorageVolumePreviewRes res = new StorageVolumePreviewRes();
        res.setPreviewRes(previewResList);
        res.setRuleRes(ruleResList);
        double usedVol = list.stream().mapToDouble(StoragePreviewDto::getVolume).sum();
        double totalVol = list.stream().mapToDouble(StoragePreviewDto::getStockCapacity).sum();
        res.setTotalVol(totalVol);
        res.setUsedVol(usedVol);
        return res;
    }


    @Override
    public void setShowRuleColor(ShowRuleColorUpdateReq req, Long userId) {
        if (req.getRuleRes() == null || req.getRuleRes().size() != 5) {
            return;
        }
        storageShowRuleDao.delete(new LambdaQueryWrapper<StorageShowRuleDo>()
                .eq(StorageShowRuleDo::getStorageId, req.getStorageId()));
        for (int i = 0; i < req.getRuleRes().size(); i++) {
            StorageShowRuleRes ruleRe = req.getRuleRes().get(i);
            StorageShowRuleDo et = new StorageShowRuleDo();
            BeanUtils.copyProperties(ruleRe, et);
            et.setStorageId(req.getStorageId());
            et.setCreateBy(userId);
            et.setCreateTime(new Date());
            if (i == 4) {
                et.setEnd(null);
            }
            storageShowRuleDao.insert(et);
        }
    }


    /**
     * 定时盘点 所有库位 对于利用率 过大 以及利用率过低 且近15天没有订单 建议合托
     */
    @Override
    public void rackMessageNotice() {
        List<StorageDo> storageDoList = storageDao.selectList(null);
        for (StorageDo storageDo : storageDoList) {
            //先获取仓库下所有的库存，按库位分
            Map<String, String> param = new HashMap<>();
            param.put("type", "1");//只看有库存的库位
            param.put("storageId", storageDo.getId() + "");
            param.put("notDefault", "1");//不看默认库位
            List<ProductStockDetailDto> stockList = productStockRackDao.getStockList(param);
            Map<Long, List<ProductStockDetailDto>> stockListMap = stockList.stream().collect(Collectors.groupingBy(ProductStockDetailDto::getRackId));

            List<StoragePreviewDto> list = positionDao.getPositionByStorageId(storageDo.getId(), null);
            for (StoragePreviewDto previewDto : list) {
                if (previewDto.getCapacityPercent() >= 100) {
                    //利用率不正常 需要盘点
                    messageNoticeService.noticeAdd(StaticDict.Message_Notice_Type.RackMore.getValue(), previewDto.getId(), "库位："+previewDto.getPositionName()+"利用率异常", "仓库："+storageDo.getStorageName()+", 库位："+previewDto.getPositionName()+" 利用率已达："+MathUtils.numberFormat(previewDto.getCapacityPercent()+"", 2)+"%, 请及时盘点确认", null, null);
                }
                else if (previewDto.getCapacityPercent() > 0 && previewDto.getCapacityPercent() <= 10) {
                    //查询库位上有哪些商品
                    List<ProductStockDetailDto> rackStockList = stockListMap.get(previewDto.getId());
                    if (rackStockList == null || rackStockList.size() == 0) {
                        continue;
                    }
                    List<Long> productId = rackStockList.stream().map(ProductStockDetailDto::getProductId).filter(Objects::nonNull).collect(Collectors.toList());
                    if (productId.size() == 0) {
                        continue;
                    }
                    //利用率过低 判断需不需要合托  查看近15有没有订单
                    int count = productOutDao.selectCount(new LambdaQueryWrapper<ProductOutDo>().in(ProductOutDo::getProductId, productId)
                            .gt(ProductOutDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -14), "yyyy-MM-dd HH:mm:ss")));
                    if (count == 0) {
                        //近15没有订单 合托建议
                        messageNoticeService.noticeAdd(StaticDict.Message_Notice_Type.RackLess.getValue(), previewDto.getId(), "库位："+previewDto.getPositionName()+"利用率过低", "仓库："+storageDo.getStorageName()+", 库位："+previewDto.getPositionName()+" 利用率只有："+MathUtils.numberFormat(previewDto.getCapacityPercent()+"", 2)+"%, 且近15天没有订单,建议合托", null, null);

                    }

                }
            }
        }
    }

}
